package com.rock.upms.client.shiro.session;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.ValidatingSession;
import org.apache.shiro.session.mgt.eis.CachingSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.rock.common.util.ByteUtil;
import com.rock.common.util.RedisUtil;
import com.rock.common.util.SerializeUtil;
import com.rock.upms.client.config.Global;
import com.rock.upms.model.dto.UserInfo;
import redis.clients.jedis.Jedis;

/**
 * 基于redis的sessionDao，缓存共享session Created by hotdog on 2018/2/23.
 */
public class UpmsSessionDao extends CachingSessionDAO {

	private static final Logger log = LoggerFactory.getLogger(UpmsSessionDao.class);

	@Override
	protected Serializable doCreate(Session session) {
		Serializable sessionId = generateSessionId(session);
		assignSessionId(session, sessionId);
		RedisUtil.set(ByteUtil.getByteKey(Global.SHIRO_SESSIONID, sessionId), SerializeUtil.serialize(session), (int) session.getTimeout() / 1000);
		log.debug("doCreate >>>>> sessionId={}", sessionId);
		return sessionId;
	}

	@Override
	protected Session doReadSession(Serializable sessionId) {
		byte[] session = RedisUtil.get(ByteUtil.getByteKey(Global.SHIRO_SESSIONID, sessionId));
		log.debug("doReadSession >>>>> sessionId={}", sessionId);
		return (Session) SerializeUtil.deserialize(session);
	}

	@Override
	protected void doUpdate(Session session) {
		// 如果会话过期/停止 没必要再更新了
		if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
			return;
		}
		RedisUtil.set(ByteUtil.getByteKey(Global.SHIRO_SESSIONID, session.getId()), SerializeUtil.serialize(session), (int) session.getTimeout() / 1000);
		log.debug("doUpdate >>>>> sessionId={}", session.getId());
	}

	@Override
	protected void doDelete(Session session) {
		String sessionId = session.getId().toString();
		// 客户端退出是全局退出
		if ("client".equals(Global.getSSOClientType())) {
			// 获取token
			byte[] tokenByte = RedisUtil.hget(ByteUtil.getByteKey(Global.SSO_CLIENT_SESSIONID, sessionId), "token".getBytes());
			String token="";
			if(tokenByte!=null){
				token=(String)SerializeUtil.deserialize(tokenByte);
			}
			
			// 根据token获取全局sessionid
			String serverSessionId = RedisUtil.get(Global.SSO_TOKEN + token);
			Jedis jedis = RedisUtil.getJedis();
			// 清除当前token对应的所有局部会话列表
			jedis.del(Global.SSO_TOKEN_CLIENT_SESSIONID_SET + token);
			jedis.del(ByteUtil.getByteKey(Global.SSO_CLIENT_SESSIONID, sessionId));// 移除局部会话
			jedis.del(Global.SSO_TOKEN + token);// 移除全局token
			jedis.del(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, serverSessionId));// 移除全局session
			jedis.close();
		}
		if ("server".equals(Global.getSSOClientType())) {
			// 当前全局会话token
			
			byte[] tokenByte = RedisUtil.hget(ByteUtil.getByteKey(Global.SSO_CLIENT_SESSIONID, sessionId), "token".getBytes());
			String token="";
			if(tokenByte!=null){
				token=(String)SerializeUtil.deserialize(tokenByte);
			}
			
			// 维护全局会话id列表
			Jedis jedis = RedisUtil.getJedis();
			jedis.del(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, sessionId));
			// 清除token
			jedis.del(Global.SSO_TOKEN + token);
			// 清除token对应的局部会话
			Set<String> clientSessionIds = jedis.smembers(Global.SSO_TOKEN_CLIENT_SESSIONID_SET + token);
			for (String clientSessionId : clientSessionIds) {
				jedis.del(ByteUtil.getByteKey(Global.SSO_CLIENT_SESSIONID, clientSessionId));
			}
			log.debug("当前token={}，对应客户端个数：{}个", token, jedis.scard(ByteUtil.getByteKey(Global.SSO_TOKEN_CLIENT_SESSIONID_SET, token)));
			jedis.del(ByteUtil.getByteKey(Global.SSO_TOKEN_CLIENT_SESSIONID_SET, token));
			jedis.close();
		}
		// 删除session
		RedisUtil.remove(ByteUtil.getByteKey(Global.SHIRO_SESSIONID, sessionId));
		log.debug("doUpdate >>>>> sessionId={}", sessionId);
	}

	/**
	 * 分页方式获取会话列表
	 * 
	 * @param offset
	 * @param limit
	 * @return
	 */
	public HashMap getActiveSessionsUserInfo(int offset, int limit) {
		HashMap<String, Object> activeUserInfo = new HashMap<String, Object>();
		Jedis jedis = RedisUtil.getJedis();
		// 获取在线会话总数
		long total = jedis.llen(Global.SSO_SERVER_SESSIONID_LIST);
		// 获取当前页会话详情
		List<String> ids = jedis.lrange(Global.SSO_SERVER_SESSIONID_LIST, offset, (offset + limit - 1));
		List<UserInfo> rows = new ArrayList<>();
		for (String id : ids) {
			byte[] catchUserInfo = RedisUtil.hget(ByteUtil.getByteKey(Global.SSO_SERVER_SESSIONID, id), "userInfo".getBytes());
			UserInfo userInfo = (UserInfo) SerializeUtil.deserialize(catchUserInfo);
			if (userInfo != null) {
				rows.add(userInfo);
			}
		}
		jedis.close();
		activeUserInfo.put("total", total);
		activeUserInfo.put("rows", rows);
		return activeUserInfo;
	}


}
